// ---------------------------------------------------------------------
// erreur.c
// ---------------------------------------------------------------------

#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <mqueue.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <config.h>
#include <simulation.h>
#include <erreur.h>



void * Erreur()
{
	// ---------------------------------------------------------------------
	// Initialisation
	// ---------------------------------------------------------------------

	// Déclaration des variables
	int bytes_read;
	mqd_t queue_handle_versErreur;
	mqd_t queue_handle_retErreur;
	mqd_t queue_handle_versArchivage;
	mqd_t queue_handle_decisionErreur;
	mqd_t queue_handle_versEcriture;


	// Récupération de BAL_versErreur
	queue_handle_versErreur=  mq_open(BAL_versErreur, O_RDWR);
	if (queue_handle_versErreur == -1)
	{
		perror ("[Erreur] Error Opening MQ BAL_versErreur:");
	}

	// Récupération de BAL_retErreur
	queue_handle_retErreur=  mq_open(BAL_retErreur, O_RDWR);
	if (queue_handle_retErreur == -1)
	{
		perror ("[Erreur] Error Opening MQ BAL_retErreur:");
		return 0;
	}

	// Récupération de BAL_versArchivage
	queue_handle_versArchivage=  mq_open(BAL_versArchivage, O_RDWR);
	if (queue_handle_versArchivage == -1)
	{
		perror ("[Erreur] Error Opening MQ BAL_versArchivage:");
	}

	// Récupération de BAL_decisionErreur
	queue_handle_decisionErreur=  mq_open(BAL_decisionErreur, O_RDWR);
	if (queue_handle_decisionErreur == -1)
	{
		perror ("[Erreur] Error Opening MQ BAL_decisionErreur:");
		return 0;
	}

	// Récupération de BAL_versEcriture
	queue_handle_versEcriture=  mq_open(BAL_versEcriture, O_RDWR);
	if (queue_handle_versEcriture == -1)
	{
		perror ("[Erreur] Error Opening MQ BAL_versEcriture:");
		return 0;
	}

	// Entier qui précise si on reprend sur un AU
	int repriseAU = 0;
	
	
	// ---------------------------------------------------------------------
	// Moteur
	// ---------------------------------------------------------------------

	for (; ;)
	{ 
		sleep(1);

		// Attente du dépot d'un message d'erreur dans la boite aux lettres
		MSG_versErreur messageErreurRecu;
		bytes_read = mq_receive(queue_handle_versErreur, (char*) &messageErreurRecu, sizeof(MSG_versErreur), NULL);

		if (bytes_read == -1)
		{
			perror("[Erreur] Failed to recieve BAL_versErreur:");
		}
		else
		{
			// -----------------------------------
			// On récupère le message 
			// -----------------------------------
			int erreurSource = messageErreurRecu.source;
			int erreurMessage = messageErreurRecu.message;
			int erreurHeure = messageErreurRecu.heure;
			int erreurNumLot = messageErreurRecu.numLot;
			int erreurCartonEnCours = messageErreurRecu.cartonEnCours;
			
			
			if (repriseAU == 1 && erreurMessage == ABS_PIECE)
			{
				// On lit seulement le message car on a deja répondu
				
				// On remet 0 a reprise
				repriseAU = 0;
			}
			else
			{
				// -----------------------------------
				// On ferme le clapet
				// -----------------------------------
				FermetureClapet();

				
				
				#ifdef DEBUG
				printf("[ERREUR] MessageVersErreur : Source %d, Message %d, numLot %d, cartonEnCours %d \n", erreurSource, erreurMessage, erreurNumLot, erreurCartonEnCours); 
				#endif

				
				// -----------------------------------
				// On Teste si la production est terminée
				// -----------------------------------
				if (erreurMessage == FIN_PROD)
				{
					// On ferme les boites au lettres
					mq_close(queue_handle_versErreur);
					mq_close(queue_handle_retErreur);
					mq_close(queue_handle_versArchivage);
					mq_close(queue_handle_decisionErreur);
					mq_close(queue_handle_versEcriture);
					
					// On se suicide
					printf("[ERREUR] : Terminaison Erreur sur FIN_PROD \n");
					pthread_exit(0);
				}
				

				// -----------------------------------
				// On dépose un message pour Archivage
				// -----------------------------------

				// Création du message
				MSG_versArchivage messageVersArchivage;
				messageVersArchivage.source = erreurSource;
				messageVersArchivage.message = erreurMessage;
				messageVersArchivage.heure = erreurHeure;
				messageVersArchivage.numLot = erreurNumLot;
				messageVersArchivage.cartonEnCours = erreurCartonEnCours;
				messageVersArchivage.type = ERREUR;


				// Envoie du message pour Archivage
				if (0 != mq_send (queue_handle_versArchivage, (const char*) &messageVersArchivage, sizeof(MSG_versArchivage), PRIO_MSG_L))
				{
					perror ("[Erreur] Sending to BAL_versArchivage:");
				}


				// -----------------------------------
				// On lance le mode dialogue opérateur
				// -----------------------------------

				// Création du message pour Ecriture
				MSG_versEcriture messageVersEcriture;
				messageVersEcriture.typeMessage = ERREUR;
				messageVersEcriture.message = erreurMessage;
				messageVersEcriture.heure = erreurHeure;
				messageVersEcriture.numLot = erreurNumLot;
				messageVersEcriture.cartonEnCours = erreurCartonEnCours;

				// Envoie du message pour Ecriture 
				if (0 != mq_send (queue_handle_versEcriture, (const char*) &messageVersEcriture, sizeof(MSG_versEcriture), PRIO_MSG_XL))
				{
					perror ("[Erreur] Sending to BAL_versEcriture:");
				}

				// -----------------------------------
				// On attend la réponse de l'opérateur
				// -----------------------------------

				#ifdef DEBUG
				printf("[ERREUR] Attente reponse operateur\n");
				#endif

				// Réception du message de l'opérateur
				MSG_decisionErreur messagedecisionErreur;
				bytes_read = mq_receive(queue_handle_decisionErreur, (char*) &messagedecisionErreur, sizeof(MSG_decisionErreur), NULL);

				if (bytes_read == -1)
				{
					perror("[Erreur] Failed to recieve BAL_decisionErreur:");
				}

				// On récupère la structure du message
				int decisionOperateur = messagedecisionErreur.reponse;
				
				#ifdef DEBUG
				printf("[ERREUR] Reponse operateur : %d \n", decisionOperateur);
				#endif


				// -----------------------------------
				// On teste selon le choix de l'opérateur
				// -----------------------------------

				// On instancie le message de retour
				MSG_retErreur messageRetErreur;
				messageRetErreur.dest = erreurSource;
				
				if (decisionOperateur == FIN_APPLI)
				{
					// Arrêt de l'activité
					messageRetErreur.reponse = FIN_APPLI;
					
					// On teste selon la provenance de l'erreur
					if ( erreurSource == T_AU )
					{
						// Si l'erreur provient de l'arret d'urgence
						messageRetErreur.dest = T_CONDITIONNEMENT;				
					}
					
					// Envoie le message en trois exemplaires
					int i;
					for (i=1; i<= 3; i++)
					{
						if (0 != mq_send (queue_handle_retErreur, (const char*) &messageRetErreur, sizeof(MSG_retErreur), PRIO_MSG_L))
						{
							perror ("[Erreur] Sending to BAL_versArchivage:");
						}
					}

					#ifdef DEBUG
					printf("[ERREUR] Envoie Ret Erreur FIN_APPLI\n");
					#endif

					// On ferme les boites au lettres
					mq_close(queue_handle_versErreur);
					mq_close(queue_handle_retErreur);
					mq_close(queue_handle_versArchivage);
					mq_close(queue_handle_decisionErreur);
					mq_close(queue_handle_versEcriture);
					
					// On se suicide
					#ifdef DEBUG
					printf("[ERREUR] : Terminaison Erreur sur FIN_APPLI \n");
					#endif
					pthread_exit(0);
				}
				else
				{
					// Reprise de l'activité
					messageRetErreur.reponse = REPRISE;
					
					repriseAU = 0;
					
					
					// On teste selon la provenance de l'erreur
					if ( erreurSource == T_AU )
					{
						#ifdef DEBUG
						printf("[ERREUR] : Reprise d'arret d'urgence \n");
						#endif
						// Si l'erreur provient de l'arret d'urgence
						messageRetErreur.dest = T_CONDITIONNEMENT;
						
						// Reprise sur Arret Urgence
						repriseAU =1;
						
						// On attend que Conditionnement se mette en erreur
						sleep(8);
					}
					
					// Envoie du message de reprise
					if (0 != mq_send (queue_handle_retErreur, (const char*) &messageRetErreur, sizeof(MSG_retErreur), PRIO_MSG_L))
					{
						perror ("[Erreur] Sending to BAL_versArchivage:");
					}
					
					// On ouvre le clapet
					OuvertureClapet();
				}     
			}
		}  
	}	
}



